//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"

//SAGITTARIUS headers:
#include "sagittarius/unicode/CUnicode.h"
#include "sagittarius/lexer/lDeriv.h"
#include "sagittarius/io/io.h"

#include <stdio.h>
//#include <time.h>
//#include <malloc.h>
//#include <string.h>

/// lex_computeDerivative
lASTNode* lex_computeDerivative(lASTNode* n, LXConstAlphaType c, int closure) {
    AN(n);
	{
		lASTNode* r = n->n1;
		lASTNode* s = n->n2;
		lASTNode *u, *v, *d;
    
		//SG_WRITE(2, "Computing Derivative:\n");
		//lex_writeOut(2, n, 0);
    
		if(n->closed && closure) {
			u = lex_computeDerivative(n, c, 0);
			d = lex_constructNodeConcat(u, n);
			lAST_destroy_node(u);
			//SG_WRITE(2, "Returning:\n");
			//lex_writeOut(2, d, 0);
			return d;
		}
		if(n->type == AST_NODE_TYPE_REPRIMITIVE) {
            int contain = re_CSContains(n->cs, c);
			/*SG_WRITE(2, "Range contains: ");
			sg_writeInt(2, re_CSContains(n->cs, c));
			SG_WRITE(2, "\n");*/
            if(n->inv)
                contain = !contain;
			return contain ? lex_constructEmptyStr() : lex_constructNull();
		}
		switch(n->type) {
			case AST_NODE_TYPE_RECONCAT:
				/*SG_WRITE(2, "Addr of r: ");
				sg_writePtr(2, r);
				SG_WRITE(2, "\n");*/
				u = lex_computeDerivative(r, c, 1);
				//SG_WRITE(2, "r->nullable u1:\n");
				//lex_writeOut(2, u, 0);
				v = lex_constructNodeConcat(u, s);
				lAST_destroy_node(u);
				if(r->nullable) {
					//SG_WRITE(2, "r->nullable v:\n");
					//lex_writeOut(2, v, 0);
					u = lex_computeDerivative(s, c, 1);
					//SG_WRITE(2, "r->nullable u:\n");
					//lex_writeOut(2, u, 0);
					d = lex_constructNodeUnion( v, u );
					lAST_destroy_node(u);
					lAST_destroy_node(v);
					//SG_WRITE(2, "r->nullable Returning:\n");
					//lex_writeOut(2, d, 0);
                    //inverse case:
                    if(n->inv)
                        d->inv = 1;
					return d;
				} else {
                    //inverse case:
                    if(n->inv)
                        v->inv = 1;
					return v;
				}
			case AST_NODE_TYPE_REUNION:
				u = lex_computeDerivative(r, c, 1);
				v = lex_computeDerivative(s, c, 1);
				d = lex_constructNodeUnion( u, v );
				lAST_destroy_node(u);
				lAST_destroy_node(v);
				return d;
            case AST_NODE_TYPE_REINTERSECTION:
                u = lex_computeDerivative(r, c, 1);
                v = lex_computeDerivative(s, c, 1);
                d = lex_constructNodeInt( u, v );
                lAST_destroy_node(u);
                lAST_destroy_node(v);
                return d;
			default:
				AN(0);
		}
	}
}

/// lex_computeDerivativeV
lexvec* lex_computeDerivativeV(lexvec* v, LXConstAlphaType c) {
    lexvece* e;
    size_t n;
    lexvec* u = create_lexvec();
    u->n = v->n;
    u->e = LX_ALLOC(v->n*sizeof(lexvece*));
    for(n=0; n<v->n; ++n) {
        e = create_lexvece();
        e->r = lex_computeDerivative(v->e[n]->r, c, 1);
        e->id = v->e[n]->id;
        e->ownid = 0;
        e->exp = v->e[n]->exp;
        e->ownexp = 0;
        e->act = v->e[n]->act;
        e->ownact = 0;
        u->e[n] = e;
    }
    return u;
}

